package org.tp.framework.filter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.tp.framework.annotation.Autowired;
import org.tp.framework.annotation.Init;
import org.tp.framework.annotation.MvcMapping;
import org.tp.framework.container.BeanContainer;
import org.tp.framework.container.MvcMappingContainer;
import org.tp.framework.interfaces.IRunInit;
import org.tp.framework.mapping.Mapping;
import org.tp.framework.util.ClassUtils;
import org.tp.framework.util.StringUtils;

public class FrameworkInit {

    public static void init(String... packageName)
            throws IllegalArgumentException, IllegalAccessException, InstantiationException {
        Set<Class<?>> clazzs = new HashSet<>();

        for (String name : packageName) {
            clazzs.addAll(ClassUtils.initClassSet(name));
        }

        proxyInitClass(clazzs);
        initClass(clazzs);
        initField();
        initMvc();
        initRun(clazzs);

    }

    // 初始化所有需要增强的类
    private static void proxyInitClass(Set<Class<?>> clazz) {
        if (clazz == null) {
            return;
        }
        for (Class<?> cla : clazz) {
            Init init = cla.getAnnotation(Init.class);
            if (init == null) {
                continue;
            }
            Method[] methods = cla.getDeclaredMethods();

            if (methods.length == 0) {
                continue;
            }

        }
    }

    // 将所有的类放入容器中
    private static void initClass(Set<Class<?>> clazz) throws InstantiationException, IllegalAccessException {
        if (clazz == null) {
            return;
        }
        for (Class<?> cla : clazz) {
            String beanName = BeanContainer.getBeanName(cla);
            if (StringUtils.isEmpty(beanName)) {
                continue;
            }
            if (BeanContainer.containerBean(beanName)) {
                continue;
            }
            Object obj = cla.newInstance();
            BeanContainer.addBeanContainer(beanName, obj);
        }

    }

    // 执行需要在系统启动时初始化的类
    private static void initRun(Set<Class<?>> clazz) {
        if (clazz == null) {
            return;
        }
        for (Class<?> cla : clazz) {
            if (!IRunInit.class.isAssignableFrom(cla)) {
                continue;
            }
            IRunInit init = BeanContainer.getBean(cla);
            if (init == null) {
                continue;
            }
            init.init();
        }

    }

    // 初始化IOC容器
    private static void initField() throws IllegalArgumentException, IllegalAccessException, InstantiationException {
        for (Object bean : BeanContainer.getBeans()) {
            List<Field> fields = ClassUtils.getClassFields(bean.getClass());
            if (fields == null || fields.isEmpty()) {
                continue;
            }
            for (Field field : fields) {
                Autowired autowired = field.getAnnotation(Autowired.class);
                if (autowired == null) {
                    continue;
                }
                String beanName = autowired.name();
                if (StringUtils.isEmpty(beanName)) {
                    beanName = field.getType().getSimpleName();
                }
                Object writeValue = null;
                field.setAccessible(true);
                if (!BeanContainer.containerBean(beanName)) {
                    writeValue = field.getClass().newInstance();
                    BeanContainer.addBeanContainer(beanName, writeValue);
                }
                writeValue = BeanContainer.getBean(beanName);
                field.set(bean, writeValue);
            }

        }

    }

    // 初始化mvc容器
    public static void initMvc() {
        for (Object bean : BeanContainer.getBeans()) {
            if (bean == null) {
                continue;
            }
            MvcMapping classMapping = bean.getClass().getAnnotation(MvcMapping.class);
            if (classMapping == null) {
                continue;
            }
            Method[] methods = bean.getClass().getDeclaredMethods();
            for (Method method : methods) {
                MvcMapping methodMapping = method.getAnnotation(MvcMapping.class);
                if (methodMapping == null) {
                    continue;
                }
                String path = classMapping.url() + methodMapping.url();
                if (MvcMappingContainer.containUrl(path)) {
                    continue;
                }
                Mapping mapping = new Mapping();
                mapping.setUrl(path);
                mapping.setRequestMethod(methodMapping.method());
                mapping.setMethod(method);
                mapping.setObject(bean);
                try {
                    mapping.setParamMap(ClassUtils.getMethodParams(method));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                MvcMappingContainer.addMapping(mapping);
            }

        }

    }

}
